/*
 * Copyright (c) 2025 李伟国
 * SQL-API is licensed under Mulan PSL v2.
 * You can use this software according to the terms and conditions of the Mulan
 * PSL v2.
 * You may obtain a copy of Mulan PSL v2 at:
 *          http://license.coscl.org.cn/MulanPSL2
 * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY
 * KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
 * NON-INFRINGEMENT, MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
 * See the Mulan PSL v2 for more details.
 */
package com.moyu.sql.business.service.impl;

import com.moyu.sql.business.config.DynamicRouterConfig;
import com.moyu.sql.business.constant.ParamsSiteEnum;
import com.moyu.sql.business.entity.MoyuRouter;
import com.moyu.sql.business.entity.MoyuSqlParam;
import com.moyu.sql.business.service.IMoyuRequestService;
import com.moyu.sql.business.service.IMoyuRouterService;
import com.moyu.sql.business.service.IMoyuSqlParamService;
import com.moyu.sql.business.utils.ParamUtils;
import com.moyu.sql.response.SuccessResponseData;
import jakarta.annotation.Resource;
import jakarta.servlet.ServletException;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.servlet.function.*;

import java.io.IOException;
import java.util.*;


@Service
public class MoyuRequestServiceImpl implements IMoyuRequestService {

    @Resource
    private IMoyuRouterService moyuRouterService;

    @Resource
    private IMoyuSqlParamService moyuSqlParamService;

    @Resource
    private DynamicRouterConfig dynamicRouterConfig;

    /**
     * 构建请求路由
     * 构建路由必须是同步的
     */
    @Override
    public void buildRequestRouter() {
        List<MoyuRouter> reuqestRouterList = moyuRouterService.getReuqestRouterList();
        if (ObjectUtils.isEmpty(reuqestRouterList)) {
            return;
        }
        RouterFunctions.Builder route = RouterFunctions.route();
        for (MoyuRouter moyuRouter : reuqestRouterList) {
            buildRequestRouterNode(route, moyuRouter);
        }
        route.GET("/health", request -> ServerResponse.ok().body(new SuccessResponseData("OK")));
        dynamicRouterConfig.updateRouter(route.build());
    }

    /**
     * 构建请求路由
     * 构建路由必须是同步的
     */
    public void buildRequestRouterNode(MoyuRouter moyuRouter) {
        RouterFunctions.Builder route = RouterFunctions.route();
        buildRequestRouterNode(route, moyuRouter);
        dynamicRouterConfig.updateRouter(route.build());
    }

    /**
     * 构建请求路由节点
     *
     * @param moyuRouter 请求路由
     */
    public void buildRequestRouterNode(RouterFunctions.Builder route, MoyuRouter moyuRouter) {
        if (ObjectUtils.isEmpty(moyuRouter.getRequestMethod()) || ObjectUtils.isEmpty(moyuRouter.getRouterFullPath())) {
            return;
        }

        if (moyuRouter.getRequestMethod().equals(RequestMethod.GET)) {
            route.GET(moyuRouter.getRouterFullPath(), RequestPredicates.contentType(MediaType.ALL),
                    this::requestHandler);
        } else if (moyuRouter.getRequestMethod().equals(RequestMethod.POST)) {
            route.POST(moyuRouter.getRouterFullPath(), RequestPredicates.contentType(MediaType.ALL),
                    this::requestHandler);
        } else if (moyuRouter.getRequestMethod().equals(RequestMethod.PUT)) {
            route.PUT(moyuRouter.getRouterFullPath(), RequestPredicates.contentType(MediaType.ALL),
                    this::requestHandler);
        } else if (moyuRouter.getRequestMethod().equals(RequestMethod.DELETE)) {
            route.DELETE(moyuRouter.getRouterFullPath(), RequestPredicates.contentType(MediaType.ALL),
                    this::requestHandler);
        }
    }

    /**
     * 请求处理
     *
     * @param request 请求
     * @return 响应
     */
    private ServerResponse requestHandler(ServerRequest request) {
        String routerPath = request.path();
        HttpMethod method = request.method();

        // 获取路由信息
        MoyuRouter moyuRouter = moyuRouterService.getByFullPathAndMethod(routerPath, RequestMethod.resolve(method));
        if (ObjectUtils.isEmpty(moyuRouter) || ObjectUtils.isEmpty(moyuRouter.getSqlId())) {
            return ServerResponse
                    .notFound()
                    .build();
        }

        // 获取参数
        List<MoyuSqlParam> moyuSqlParams = moyuSqlParamService.selectBySqlParamGroupId(moyuRouter.getParamGroupId());

        // 构建请求参数
        // 地址传参
        Map<String, Object> paramsMap = new LinkedHashMap<>();
        // 处理地址传参
        paramsMap.putAll(getSqlParamMap(moyuSqlParams, request));
        // 处理body传参
        paramsMap.putAll(getRequestBodyParamsMap(moyuSqlParams, request));

        // 执行请求
        Object executeResult = moyuRouterService.execute(routerPath, method, paramsMap);
        return ServerResponse
                .ok()
                .body(new SuccessResponseData(executeResult));
    }

    public Map<String, Object> getSqlParamMap(List<MoyuSqlParam> moyuSqlParams, ServerRequest request) {
        Map<String, Object> paramsMap = new LinkedHashMap<>();
        if (!ObjectUtils.isEmpty(moyuSqlParams)) {
            for (MoyuSqlParam moyuSqlParam : moyuSqlParams) {
                if (!Arrays.asList(ParamsSiteEnum.PATH, ParamsSiteEnum.ANY, ParamsSiteEnum.DEFAULT).contains(moyuSqlParam.getParamSite())) {
                    continue;
                }
                String requestParamValue = request.param(moyuSqlParam.getParamName()).orElse(null);
                if (moyuSqlParam.getIsRequired() && ObjectUtils.isEmpty(requestParamValue)) {
                    throw new RuntimeException("参数" + moyuSqlParam.getParamName() + "不能为空");
                }
                paramsMap.put(moyuSqlParam.getParamName(), requestParamValue);
            }
        }
        return paramsMap;
    }

    public Map<String, Object> getRequestBodyParamsMap(List<MoyuSqlParam> moyuSqlParams, ServerRequest request) {
        Map<String, Object> bodyParamsMap = Map.of();
        if (RequestMethod.resolve(request.method()) == RequestMethod.POST ||
                RequestMethod.resolve(request.method()) == RequestMethod.PUT) {
            try {
                bodyParamsMap = request.body(new ParameterizedTypeReference<>() {
                });
            } catch (ServletException | IOException e) {
                throw new RuntimeException(e);
            }
            // 判断是否有必填参数未填
            if (!ObjectUtils.isEmpty(moyuSqlParams)) {
                for (MoyuSqlParam moyuSqlParam : moyuSqlParams) {
                    if (!Arrays.asList(ParamsSiteEnum.BODY, ParamsSiteEnum.ANY, ParamsSiteEnum.DEFAULT).contains(moyuSqlParam.getParamSite())) {
                        continue;
                    }
                    Object nestedParamValue = ParamUtils.getNestedParamValue(moyuSqlParam.getParamName(), bodyParamsMap);
                    if (moyuSqlParam.getIsRequired() && ObjectUtils.isEmpty(nestedParamValue)) {
                        throw new RuntimeException("参数" + moyuSqlParam.getParamName() + "不能为空");
                    }
                }
            }
        }
        return bodyParamsMap;
    }

}
